#include "rectangle.h"
#include <GL/gl.h>
#include "utils.h"

Rectangle::Rectangle(const Point &p1, const Point &p2, const Point &p3, const Point &p4)
    : p1_(p1), p2_(p2), p3_(p3), p4_(p4), plane_(p1, vecprod(p2 - p1, p3 - p1))
{
    material_.set_ambient(CgColor(0.0, 0.4, 0.0));
    material_.set_diffuse(CgColor(0.0, 0.4, 0.0));
    material_.set_specular(CgColor(0.0, 0.0, 0.0));
}

bool Rectangle::intersect(const Ray &r, double &t, Vector &normal) const
{
    normal = plane_.normal();
    double denominator = plane_.normal() * r.dir();

    if( compare_equals(denominator, 0.0) )
        return false;

    t = -plane_.d() / denominator;
    if( !compare_equals(t, 0.0) ) {                    // if hits rectangle plane
        const Vector vx = t*r.dir();
        const Point x(vx(0), vx(1), vx(2));

        return intersectTriangle(x, p1_, p2_, p3_) ||
               intersectTriangle(x, p3_, p4_, p1_);     // tests intersection with the two triangles that define the rectangle
    }

    return false;
}

void Rectangle::openGlRender() const
{
    GLfloat gl_ambient[] = {material_.ambient().r(), material_.ambient().g(), material_.ambient().b(), 1.0};
    GLfloat gl_diffuse[] = {material_.diffuse().r(), material_.diffuse().g(), material_.diffuse().b(), 1.0};
    GLfloat gl_specular[] = {material_.specular().r(), material_.specular().g(), material_.specular().b(), 1.0};
    Vector normal = plane_.normal();
    GLdouble glnormal[] = {normal(0), normal(1), normal(2)};

    glMaterialfv(GL_FRONT, GL_AMBIENT, gl_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, gl_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, gl_specular);

    glBegin(GL_QUADS);
        glNormal3dv(glnormal);
        glVertex3dv(p1_.toCArray());
        glVertex3dv(p2_.toCArray());
        glVertex3dv(p3_.toCArray());
        glVertex3dv(p4_.toCArray());
    glEnd();
}

// We omit the ray-plane intersection test in the triangle since this method will be used in a context
// where we already know that the ray intersects the triangle plane.
bool Rectangle::intersectTriangle(const Point &x, const Point &p1, const Point &p2, const Point &p3) const
{
    return (vecprod(p2 - p1, x - p1)*plane_.normal() >= 0) &&
           (vecprod(p3 - p2, x - p2)*plane_.normal() >= 0) &&
           (vecprod(p1 - p3, x - p3)*plane_.normal() >= 0);
}

ICgObject* Rectangle::clone() const
{
    Rectangle *c = new Rectangle(Point(-1.0, 1.0, -2.0), Point(1.0, 1.0, -2.0), Point(1.0, -1.0, -2.0), Point(-1.0, -1.0, -2.0));
    c->multiplyCurrentTransformation(this->transformation_);
    c->material_ = this->material_;
    return c;
    return 0;
}
